package com.android.demo_20220829.ui.activity;

import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattService;
import android.content.Intent;
import android.graphics.Color;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.os.SystemClock;
import android.provider.Settings;
import android.text.TextUtils;
import android.view.View;
import android.widget.EditText;
import android.widget.ProgressBar;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import androidx.appcompat.app.AppCompatActivity;
import androidx.documentfile.provider.DocumentFile;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

import com.android.baselibrary.dialog.Comm_DialogFragment;
import com.android.baselibrary.interface_.CommCallBack;
import com.android.baselibrary.tool.AndPermisionUtil;
import com.android.baselibrary.tool.CommLoading;
import com.android.baselibrary.tool.CommToast;
import com.android.baselibrary.tool.Log;
import com.android.baselibrary.tool.XXPermisionUtil;
import com.android.baselibrary.util.FileUriUtil;
import com.android.baselibrary.view.Comm_HeadView;
import com.android.baselibrary.view.MultiStateView;
import com.android.demo_20220829.R;
import com.android.demo_20220829.adapter.LogAdapter;
import com.android.demo_20220829.event.Event_SendBigBagSuccess;
import com.android.demo_20220829.manager.SendFileManager;
import com.hjq.permissions.OnPermissionCallback;
import com.yanzhenjie.permission.runtime.Permission;

import org.greenrobot.eventbus.Subscribe;

import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

import butterknife.BindView;
import butterknife.OnClick;
import cn.wandersnail.ble.Connection;
import cn.wandersnail.ble.ConnectionConfiguration;
import cn.wandersnail.ble.ConnectionState;
import cn.wandersnail.ble.Device;
import cn.wandersnail.ble.EasyBLE;
import cn.wandersnail.ble.EventObserver;
import cn.wandersnail.ble.Request;
import cn.wandersnail.ble.RequestBuilder;
import cn.wandersnail.ble.RequestBuilderFactory;
import cn.wandersnail.ble.RequestType;
import cn.wandersnail.ble.WriteCharacteristicBuilder;
import cn.wandersnail.ble.WriteOptions;
import cn.wandersnail.ble.callback.NotificationChangeCallback;
import cn.wandersnail.commons.observer.Observe;
import cn.wandersnail.commons.poster.RunOn;
import cn.wandersnail.commons.poster.Tag;
import cn.wandersnail.commons.poster.ThreadMode;
import cn.wandersnail.commons.util.FileUtils;
import cn.wandersnail.commons.util.StringUtils;
import cn.wandersnail.commons.util.ToastUtils;

public class DeviceDetailActivity extends BaseActivity implements EventObserver {

    @BindView(R.id.multiplestatusView)
    MultiStateView multiplestatusView;
    @BindView(R.id.comm_title)
    Comm_HeadView comm_title;
    @BindView(R.id.tv_state)
    TextView tv_state;
    @BindView(R.id.et_input)
    EditText et_input;
    @BindView(R.id.tv_filepath)
    TextView tv_filepath;
    @BindView(R.id.recyclerview)
    RecyclerView recyclerview;
    @BindView(R.id.tv_filesize)
    TextView tv_filesize;
    @BindView(R.id.progressbar)
    ProgressBar progressbar;


    Device info;
    Connection connection;

    float sendLength = 0;
    float fileLength = 0;

    String UUID_Service = "0000ffe0-0000-1000-8000-00805f9b34fb";
    String UUID_Characteristic_Notify = "0000ffe1-0000-1000-8000-00805f9b34fb";
    String UUID_Characteristic_Write = "0000ffe1-0000-1000-8000-00805f9b34fb";

//    String UUID_Service = "f000ffc0-0451-4000-b000-000000000000";
//    String UUID_Characteristic_Notify = "f000ffc1-0451-4000-b000-000000000000";
//    String UUID_Characteristic_Write = "f000ffc1-0451-4000-b000-000000000000";


    public static String Tag_SendFile = "SendFile";
    public static String Tag_SendData = "SendData";
    public static String Tag_SendBegin = "Tag_SendBegin";


//    飞易通ble服务
//    String UUID_Service = "0000fff0-0000-1000-8000-00805f9b34fb";
//    String UUID_Characteristic_Notify = "0000fff1-0000-1000-8000-00805f9b34fb";
//    String UUID_Characteristic_Write = "0000fff2-0000-1000-8000-00805f9b34fb";

    BluetoothGattService gattService;
    BluetoothGattCharacteristic gattCharacteristic_notify;
    BluetoothGattCharacteristic gattCharacteristic_write;
    SendFileManager sendFileManager;
    List<String> logList = new ArrayList<>();
    LogAdapter logAdapter;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        EasyBLE.getInstance().registerObserver(this);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        EasyBLE.getInstance().unregisterObserver(this);
        connection.disconnect();
    }

    @Override
    protected boolean isRegistEventbus() {
        return true;
    }

    @Override
    protected int getLayoutId() {
        return R.layout.activity_devicedetail;
    }

    @Override
    protected void initView() {
        info = getIntent().getParcelableExtra("info");
        comm_title.setTitle("设备连接");
        comm_title.setLeftImg(R.drawable.ico_back_white);

        recyclerview.setLayoutManager(new LinearLayoutManager(mContext));
        logAdapter = new LogAdapter(mContext, new CommCallBack() {
            @Override
            public void onResult(Object obj) {
                recyclerview.scrollToPosition(logAdapter.getItemCount() - 1);
            }
        });
        recyclerview.setAdapter(logAdapter);
        logAdapter.setData(logList);

        sendFileManager = new SendFileManager(mContext);
        sendFileManager.setLogAdapter(logAdapter);
    }

    @Override
    protected void initData() {

        //连接配置，举个例随意配置两项
        ConnectionConfiguration config = new ConnectionConfiguration();
        config.setConnectTimeoutMillis(10000);
        config.setRequestTimeoutMillis(1000);
        config.setAutoReconnect(false);
//        connection = EasyBLE.getInstance().connect(device, config, observer);//回调监听连接状态，设置此回调不影响观察者接收连接状态消息
        connection = EasyBLE.getInstance().connect(info, config);//观察者监听连接状态
//        connection.setBluetoothGattCallback(new BluetoothGattCallback() {
//            @Override
//            public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
//                Log.d("原始写入数据：" + StringUtils.toHex(characteristic.getValue()));
//            }
//        });

    }


    /**
     * 使用{@link Observe}确定要接收消息，{@link RunOn}指定在主线程执行方法，设置{@link Tag}防混淆后找不到方法
     */
    @Tag("onConnectionStateChanged")
    @Observe
    @RunOn(ThreadMode.MAIN)
    @Override
    public void onConnectionStateChanged(@NonNull Device device) {
        switch (device.getConnectionState()) {
            case SCANNING_FOR_RECONNECTION:

                break;
            case CONNECTING:
                Log.i("连接成功");
                tv_state.setText("连接状态：已连接");
                tv_state.setTextColor(Color.parseColor("#3589F8"));
                break;
            case DISCONNECTED:
                Log.i("连接失败");
                tv_state.setText("连接状态：未连接");
                tv_state.setTextColor(Color.parseColor("#FE461F"));
                break;
            case SERVICE_DISCOVERED:
                Log.i("连接成功");
                tv_state.setText("连接状态：已连接，已初始化服务");
                List<BluetoothGattService> services = connection.getGatt().getServices();
                for (BluetoothGattService service : services) {
                    Log.i("service.getUuid():" + service.getUuid());
                    if (service.getUuid().toString().equals(UUID_Service)) {
                        gattService = service;
                    }
                    List<BluetoothGattCharacteristic> characteristics = service.getCharacteristics();
                    for (BluetoothGattCharacteristic characteristic : characteristics) {
                        Log.i("characteristic.getUuid():" + characteristic.getUuid());
                        if (characteristic.getUuid().toString().equals(UUID_Characteristic_Notify)) {
                            gattCharacteristic_notify = characteristic;
                        }
                        if (characteristic.getUuid().toString().equals(UUID_Characteristic_Write)) {
                            gattCharacteristic_write = characteristic;
                        }
                    }
                }
                setNotification();
                sendFileManager.setConnection(connection, gattService.getUuid(), gattCharacteristic_write.getUuid());

                break;
        }
    }

    /**
     * 使用{@link Observe}确定要接收消息，方法在{@link EasyBLEBuilder#setMethodDefaultThreadMode(ThreadMode)}指定的线程执行
     */
    @Observe
    @Override
    public void onNotificationChanged(@NonNull Request request, boolean isEnabled) {
        if (request.getType() == RequestType.SET_NOTIFICATION) {
            if (isEnabled) {
                Log.d("通知开启了");
            } else {
                Log.d("通知关闭了");
            }
        } else {
            if (isEnabled) {
                Log.d("Indication开启了");
            } else {
                Log.d("Indication关闭了");
            }
        }
    }

    /**
     * 如果{@link EasyBLEBuilder#setObserveAnnotationRequired(boolean)}设置为false时，无论加不加{@link Observe}注解都会收到消息。
     * 设置为true时，必须加{@link Observe}才会收到消息。
     * 默认为false，方法默认执行线程在{@link EasyBLEBuilder#setMethodDefaultThreadMode(ThreadMode)}指定
     */
    @Override
    public void onCharacteristicWrite(@NonNull Request request, @NonNull byte[] value) {
        String hexStr = StringUtils.toHex(value, " ");
//        CommToast.showToast(mContext, "发送成功");
        if (request.getTag().equals(Tag_SendFile)) {
            Log.d("成功发送小包："+ value.length+ ":"+hexStr);
            SystemClock.sleep(50);
            sendFileManager.sendSmallBag();
        } else if (request.getTag().equals(Tag_SendData)) {
            Log.d("成功发送文字数据："+ hexStr);
            logAdapter.addLog(">>> 文字发送成功：" + hexStr);
        } else if (request.getTag().equals(Tag_SendBegin)) {
            Log.d("成功发送开始数据："+ hexStr);
            logAdapter.addLog(">>> 已发送开始指令，等待回复");
        }
    }

    @Override
    public void onCharacteristicRead(@NonNull Request request, @NonNull byte[] value) {
        String hexStr = StringUtils.toHex(value, " ");
        Log.w("收到设备主动发送来的数据:" + hexStr);
        logAdapter.addLog("<<< 收到数据：" + hexStr);

    }

    /**
     * notification数据
     *
     * @param device         设备
     * @param service        服务UUID
     * @param characteristic 特征UUID
     * @param value          数据
     */
    @Override
    public void onCharacteristicChanged(@NonNull Device device, @NonNull UUID service, @NonNull UUID characteristic, @NonNull byte[] value) {
        String hexStr = StringUtils.toHex(value, " ");
        Log.w("收到设备主动发送来的数据:" + hexStr);
        if (value.length == 1) {
            if (value[0] == (byte) 0xE9) {
                logAdapter.addLog("<<< 收到主机回复：" + hexStr + "，开始发送数据");
                sendFileManager.sendBigBag();
            } else if (value[0] == (byte) 0x35) {
                logAdapter.addLog("<<< 收到主机回复：" + hexStr + "，继续发送数据");
                sendFileManager.sendBigBag();
            }
            else{
                logAdapter.addLog("<<< 收到主机回复：" + hexStr + "，数据校验失败");
            }
        }
        else{
            logAdapter.addLog("<<< 收到数据：" + hexStr);
        }

    }

    //开启通知
    private void setNotification() {
        boolean isEnabled = connection.isNotificationEnabled(gattService.getUuid(), gattCharacteristic_notify.getUuid());
        Log.i("isEnabled:"+ isEnabled);
        RequestBuilder<NotificationChangeCallback> builder = new RequestBuilderFactory().getSetNotificationBuilder(gattService.getUuid(), gattCharacteristic_notify.getUuid(), true);
        //不设置回调，使用观察者模式接收结果
        builder.build().execute(connection);
    }

    //发送文字
    private void writeCharacteristic(byte[] data) {
        Log.d("开始写入");
//        byte[] data = {0x5E};
        WriteCharacteristicBuilder builder = new RequestBuilderFactory().getWriteCharacteristicBuilder(gattService.getUuid(),
                gattCharacteristic_write.getUuid(), data);
        builder.setTag("single_write_test");
        //根据需要设置写入配置
        int writeType = connection.hasProperty(gattService.getUuid(), gattCharacteristic_write.getUuid(),
                BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE) ?
                BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE : BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT;
        builder.setWriteOptions(new WriteOptions.Builder()
                .setPackageSize(128)
                .setPackageWriteDelayMillis(5)
                .setRequestWriteDelayMillis(10)
                .setWaitWriteResult(true)
                .setWriteType(writeType)
                .build());
        //不设置回调，使用观察者模式接收结果
        builder.build().execute(connection);
    }


    @OnClick({R.id.tv_send, R.id.tv_select_file, R.id.tv_send_file,R.id.tv_open_note})
    public void onViewClicked(View view) {
        switch (view.getId()) {
            case R.id.tv_send:
                String text = et_input.getText().toString();
                if (TextUtils.isEmpty(text)) {
                    CommToast.showToast(mContext, "内容不能为空");
                    return;
                }
                sendFileManager.sendData(text.getBytes(), DeviceDetailActivity.Tag_SendData);
                break;
            case R.id.tv_select_file:
                getPermission();
                break;
            case R.id.tv_send_file:
                //发送开始命令
                if (sendFileManager.queue_big.size() == 0) {
                    CommToast.showToast(mContext, "请选择文件");
                    return;
                }

                byte[] data = {(byte) 0x5E};
                sendFileManager.sendData(data, DeviceDetailActivity.Tag_SendBegin);
                break;
            case R.id.tv_open_note:   //打开通知
                if(connection.getConnectionState()== ConnectionState.DISCONNECTED) {
                    connection.reconnect();
                }
                else{
                    CommToast.showToast(mContext, "设备已经连接");
                }
                break;
        }
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        switch (requestCode) {
            case REQUEST_CODE_FOR_DIR:   //返回授权信息
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
                    if (Environment.isExternalStorageManager()) {
                        CommToast.showToast(mContext, "权限获取成功,请选择文件");
                        getPermission();
                    } else {
                        CommToast.showToast(mContext, "权限获取失败");
                    }
                }
                break;
            case REQUEST_CODE_FOR_File:   //返回获取文件
                if (data != null) {
                    Uri uri = data.getData();
                    Log.i("uri.getPath:" + uri.getPath());
                    String path = FileUriUtil.getPath(mContext, uri);
                    File file = new File(path);

                    sendFileManager.setFile(new File(path));
                    tv_filepath.setText("文件路径：" + path);
                    tv_filesize.setText("文件大小：" + FileUtils.formatFileSize(file.length()));

                    fileLength = file.length();
                    sendLength = 0;
                    uploadProgress();
                }
                break;
        }
    }

    @Subscribe(threadMode = org.greenrobot.eventbus.ThreadMode.MAIN)
    public void onEventMainThread(Event_SendBigBagSuccess event) {
        sendLength += 2048;
        uploadProgress();
    }

    //更新进度
    private void uploadProgress() {
        try {
            float percent = (sendLength / fileLength)*100;
//            Log.i("sendLength:"+ sendLength + " fileLength:"+ fileLength + " percent:"+ percent);
            if(percent>100)  percent=100;
            progressbar.setProgress((int) percent);
        } catch (Exception e) {

        }
    }

    final int REQUEST_CODE_FOR_DIR = 100;
    final int REQUEST_CODE_FOR_File =200;
    //获取权限    安卓 29 = 安卓11
    private void getPermission() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R && !Environment.isExternalStorageManager()) {
            //没有权限, 跳设置
            try {
                Intent intent = new Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION);
                intent.addCategory("android.intent.category.DEFAULT");
                intent.setData(Uri.parse(String.format("package:%s", mContext.getPackageName())));
                startActivityForResult(intent, REQUEST_CODE_FOR_DIR);
            } catch (Exception e) {
                Intent intent = new Intent();
                intent.setAction(Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION);
                startActivityForResult(intent, REQUEST_CODE_FOR_DIR);
            }
        } else {
            XXPermisionUtil.requstPermision(mContext, new OnPermissionCallback() {
                @Override
                public void onGranted(List<String> permissions, boolean all) {
                    selectFile();
                }

                @Override
                public void onDenied(List<String> permissions, boolean never) {
                    OnPermissionCallback.super.onDenied(permissions, never);
                    CommToast.showToast(mContext, "没有文件读取权限");
                }
            },Permission.READ_EXTERNAL_STORAGE);

//            AndPermisionUtil.requstPermision(mContext, new AndPermisionUtil.PermisionCallBack() {
//                @Override
//                public void onGranted() {
//                    selectFile();
//                }
//
//                @Override
//                public void onDenied() {
//                    CommToast.showToast(mContext, "没有文件读取权限");
//                }
//            }, Permission.READ_EXTERNAL_STORAGE);
        }
    }

    private void selectFile() {
        Intent intent = new Intent();
        intent.setAction(Intent.ACTION_GET_CONTENT);
        intent.setType("*/*");
        intent.addCategory(Intent.CATEGORY_OPENABLE);
        startActivityForResult(intent, REQUEST_CODE_FOR_File);
    }

}
